package arithmetic.socket.nio;


import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.time.LocalDateTime;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import io.netty.util.concurrent.DefaultThreadFactory;

/**
 * 写nio的selector 模式客户端
 * <p>
 * 非阻塞方式
 *
 * @author jiangfeng
 * Created on 2020-03-28
 */
public class NioTestClient {

    public static void main(String[] args) throws Exception {
        // 建立服务端连接
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);

        Selector selector = Selector.open();
        socketChannel.register(selector, SelectionKey.OP_CONNECT);

        // 一定要先注册上,再去连接
        socketChannel.connect(new InetSocketAddress("localhost", 8899));

        while (true) {
            selector.select();
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            for (SelectionKey selectionKey : selectionKeys) {
                SocketChannel channel = null;
                if (selectionKey.isConnectable()) {
                    channel = (SocketChannel) selectionKey.channel();
                    // 是否是连接工作已准备好,只待连接  注意不是isConnection();
                    if (channel.isConnectionPending()) {
                        try {
                            channel.finishConnect();
                            System.out.println("与服务器连接成功:" + channel.getRemoteAddress());
                            // 返回服务器,连接成功
                            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                            byteBuffer.put((LocalDateTime.now() + "连接成功").getBytes());
                            byteBuffer.flip();
                            channel.write(byteBuffer);

                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        // 新启动线程写入消息(不能阻塞)
                        ExecutorService executorService = Executors.newSingleThreadExecutor();
                        SocketChannel finalChannel = channel;
                        executorService.execute(() -> {
                            while (true) {
                                ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
                                Scanner scanner = new Scanner(System.in);
                                writeBuffer.put(scanner.nextLine().getBytes());
                                writeBuffer.flip();

                                try {
                                    finalChannel.write(writeBuffer);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        });

                        // 记得连接好了后 注册可读事件
                        channel.register(selector, SelectionKey.OP_READ);
                    }
                }else if (selectionKey.isReadable()) {
                    // 接收服务器信息
                    channel = (SocketChannel) selectionKey.channel();

                    ByteBuffer readBuffer = ByteBuffer.allocate(1024);
                    try {
                        int read = channel.read(readBuffer);
                        if (read > 0) {
                            System.out.println(new String(readBuffer.array(), 0, read));
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

            selectionKeys.clear();

        }
    }
}
